package com.kmxd.ams.app.event.copy.command;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.kmxd.ams.client.archive.IArchiveTypeSvc;
import com.kmxd.ams.client.archive.vo.ArchiveTypeVO;
import com.kmxd.ams.client.arrange.IDocumentSvc;
import com.kmxd.ams.client.arrange.IProjectSvc;
import com.kmxd.ams.client.arrange.dto.DocumentCopyDTO;
import com.kmxd.ams.client.logs.ILogArchiveSvc;
import com.kmxd.ams.client.logs.dto.LogArchiveQueryDTO;
import com.kmxd.ams.client.logs.vo.LogArchiveListVO;
import com.kmxd.ams.core.common.bo.LoginUser;
import com.kmxd.ams.core.common.constant.Constants;
import com.kmxd.ams.core.common.enums.*;
import com.kmxd.ams.core.util.ConvertUtil;
import com.kmxd.ams.core.util.SecurityUtil;
import com.kmxd.ams.infra.archive.entity.ArchiveType;
import com.kmxd.ams.infra.arrange.entity.Document;
import com.kmxd.ams.infra.arrange.entity.Project;
import com.kmxd.ams.infra.logs.entity.LogArchive;
import java.util.*;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * 文档复制操作
 *
 * @author nickbi
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DocumentCopyCmd {
  private final IDocumentSvc documentSvc;
  private final ArchiveMetaFieldCmd archiveMetaFieldCmd;
  private final FileCopyCmd fileCopyCmd;
  private final ILogArchiveSvc logArchiveSvc;
  private final IArchiveTypeSvc archiveTypeSvc;

  /** 复制电子文件 */
  @Transactional(rollbackFor = Exception.class)
  public void copy(DocumentCopyDTO req, String saToken) throws Exception {
    log.debug("start copy document:{}", req);

    Document qry = new Document();
    qry.setTableId(req.getTableId());
    qry.setId(req.getId());
    qry.setArchTypeId(req.getArchTypeId());
    Document oldArch = documentSvc.view(qry);
    Map<String, String> metaFieldMap =
        archiveMetaFieldCmd.getMetaFieldMap(req.getTableId(), req.getNewDocTableId());
    // 元数据对应为空，则直接按名称复制
    Document newDocument =
        null == metaFieldMap
            ? ConvertUtil.toBean(oldArch, Document.class)
            : ConvertUtil.toMetaFieldBean(oldArch, metaFieldMap, Document.class);

    // 1条目信息，1条目信息+电子文件
    if (req.getTitleOptions().equals(ArchOperateTitleOptionsEnum.APPEND_COPY.getCode())) {
      newDocument.setTitle(Constants.COPY_PREFIX + newDocument.getTitle());
    }

    // 设置新数据的状态，一般为待整理0
    newDocument.setStatus(Optional.ofNullable(req.getStatus()).orElse(ArchStatusEnum.S0.getCode()));

    // 重置档号等信息
    newDocument.setId(null);
    // 复制，直接删除档号
    if (req.getOpType().equals(ArchOpEnum.COPY.getCode())
        && BooleanUtil.isTrue(req.getCleanArchCode())) {
      newDocument.setArchCode(null);
      newDocument.setDocSequence(null);
    } else {
      if (BooleanUtil.isTrue(req.getCleanArchCode())) {
        newDocument.setArchCode(null);
        newDocument.setDocSequence(null);
      }
    }

    if (Objects.nonNull(req.getNewProjectId())) {
      //
      IProjectSvc projectSvc = SpringUtil.getBean(IProjectSvc.class);
      Long archTypeId = Optional.ofNullable(req.getNewArchTypeId()).orElse(req.getArchTypeId());
      ArchiveTypeVO newArchType = archiveTypeSvc.view(archTypeId);
      String projTableId = newArchType.getProjTableId();
      Project qryProj = new Project();
      qryProj.setTableId(projTableId);
      qryProj.setArchTypeId(newArchType.getId());
      qryProj.setId(req.getNewProjectId());
      Project project = projectSvc.view(qryProj);
      // 设置数据
      newDocument.setProjCode(project.getProjCode());
      newDocument.setProjId(req.getNewProjectId());

    } else {
      newDocument.setProjId(null);
      newDocument.setProjCode(null);
    }

    if (null != req.getNewVolId()) {
      newDocument.setVolId(req.getNewVolId());
    } else {
      newDocument.setVolId(null);
      newDocument.setVolArchCode(null);
    }
    // 复制到其他门类时，修改门类及数据表信息
    if (null != req.getNewArchTypeId()) {
      newDocument.setArchTypeId(req.getNewArchTypeId());
    } else {
      newDocument.setArchTypeId(req.getArchTypeId());
    }
    oldArch.setArchTypeId(req.getArchTypeId());
    // 复制到其他门类时设置新的门类文档表名
    if (null != req.getNewDocTableId()) {
      newDocument.setTableId(req.getNewDocTableId());
    } else {
      newDocument.setTableId(req.getTableId());
    }
    // 清空原有关联关系盒号,项目代号,所属卷号
    newDocument.setBoxId(null);
    newDocument.setBoxNo(null);

    // 清空四性检测
    newDocument.setFourCheckId(null);
    newDocument.setFourCheckResult(null);
    newDocument.setFourCheckInfo(null);
    // 清空长期保存
    newDocument.setLongtermPreservationId(null);
    newDocument.setLongtermPreservationStatus(null);
    // 清空移交关系
    newDocument.setTransferId(null);
    newDocument.setTransferStatus(null);
    // 不复制电子文件时，清空电子文件数量
    if (!req.getType().equals(ArchOperateTypeEnum.ITEM_AND_FILE.getCode())) {
      newDocument.setFilesNum(0);
    }
    documentSvc.add(newDocument);
    log.debug("copy document:{}", newDocument);
    //
    // 复制内容，1条目信息，2条目信息+电子文件
    if (req.getType().equals(ArchOperateTypeEnum.ITEM_AND_FILE.getCode())) {
      oldArch.setArchTypeId(req.getArchTypeId());
      oldArch.setTableId(req.getTableId());
      fileCopyCmd.copy(oldArch, newDocument, req.getOpType());
    }

    // 移动操作,删除原数据,直接删除
    if (req.getOpType().equals(ArchOpEnum.MOVE.getCode())) {
      qry.setDocIds(String.valueOf(qry.getId()));
      // 此处使用真删除
      documentSvc.cleanTrash(qry);
    }
    //    saveLog(req, oldArch, newDocument, saToken);
  }

  public void saveLog(DocumentCopyDTO req, Document old, Document newDoc, String saToken) {
    LogArchiveQueryDTO qryLog = new LogArchiveQueryDTO();
    qryLog.setArchId(old.getId());
    List<LogArchiveListVO> logList = logArchiveSvc.selectList(qryLog, saToken);
    if (req.getOpType().equals(ArchOpEnum.COPY.getCode())) {
      List<LogArchive> newLogList =
          logList.stream()
              .map(
                  item -> {
                    LogArchive log = ConvertUtil.toBean(item, LogArchive.class);
                    log.setArchId(newDoc.getId());
                    log.setId(null);
                    return log;
                  })
              .collect(Collectors.toList());
      LogArchive copyLog = ConvertUtil.toBean(newDoc, LogArchive.class);
      copyLog.setArchId(newDoc.getId());
      copyLog.setType(ArchManageEnum.BECOMING.getType());
      if (ObjectUtil.equals(old.getArchTypeId(), newDoc.getArchTypeId())) {
        copyLog.setOpName(
            SecurityUtil.getLangCode().equalsIgnoreCase(Constants.DEFAULT_LANG_CODE)
                ? "新增档案"
                : "create archive");
        copyLog.setActionDescription(
            SecurityUtil.getLangCode().equalsIgnoreCase(Constants.DEFAULT_LANG_CODE)
                ? StrUtil.format(
                    "新增档案 （从\"{}\"）复制", ArchStatusEnum.convert(old.getStatus()).getDesc())
                : StrUtil.format(
                    "create archive （from \"{}\"）copy to ",
                    ArchStatusEnum.convert(old.getStatus()).getDesc()));
      } else {
        ArchiveType oldArchType = archiveTypeSvc.getById(old.getArchTypeId());
        ArchiveType newArchType = archiveTypeSvc.getById(newDoc.getArchTypeId());

        copyLog.setActionDescription(
            SecurityUtil.getLangCode().equalsIgnoreCase(Constants.DEFAULT_LANG_CODE)
                ? StrUtil.format(
                    "（从\"{}\"）复制到 \"{}\"", oldArchType.getName(), newArchType.getName())
                : StrUtil.format(
                    "（from\"{}\"）copy to  \"{}\"", oldArchType.getName(), newArchType.getName()));
        copyLog.setActionDescription(
            SecurityUtil.getLangCode().equalsIgnoreCase(Constants.DEFAULT_LANG_CODE)
                ? String.format(
                    "从门类: %s, 表: %s, 数据: %s 复制到门类: " + "%s, 表: %s, 数据: %s",
                    oldArchType.getId(),
                    old.getTableId(),
                    old.getId(),
                    newArchType.getId(),
                    newDoc.getTableId(),
                    newDoc.getId())
                : String.format(
                    "copy data from archTypeId: %s, tableId: %s, dataId: %s to archTypeId: "
                        + "%s, tableId: %s, dataId: %s",
                    oldArchType.getId(),
                    old.getTableId(),
                    old.getId(),
                    newArchType.getId(),
                    newDoc.getTableId(),
                    newDoc.getId()));
      }
      setUserInfo(saToken, copyLog);
      newLogList.add(copyLog);
      logArchiveSvc.saveBatch(newLogList);
    }

    if (req.getOpType().equals(ArchOpEnum.MOVE.getCode())) {
      ArchiveType oldArchType = archiveTypeSvc.getById(old.getArchTypeId());
      ArchiveType newArchType = archiveTypeSvc.getById(newDoc.getArchTypeId());
      LogArchive moveLog = ConvertUtil.toBean(newDoc, LogArchive.class);
      moveLog.setArchId(newDoc.getId());
      moveLog.setType(ArchManageEnum.ARRANGE.getType());
      setUserInfo(saToken, moveLog);
      moveLog.setActionDescription(
          SecurityUtil.getLangCode().equalsIgnoreCase(Constants.DEFAULT_LANG_CODE)
              ? StrUtil.format("（从\"{}\"）移动 到 \"{}\"", oldArchType.getName(), newArchType.getName())
              : StrUtil.format(
                  "（from\"{}\"）move to \"{}\"", oldArchType.getName(), newArchType.getName()));
      moveLog.setActionDescription(
          SecurityUtil.getLangCode().equalsIgnoreCase(Constants.DEFAULT_LANG_CODE)
              ? String.format(
                  "从门类: %s, 表: %s, 数据: %s 移动到类: " + "%s, 表: %s, 数据: %s",
                  oldArchType.getId(),
                  old.getTableId(),
                  old.getId(),
                  newArchType.getId(),
                  newDoc.getTableId(),
                  newDoc.getId())
              : String.format(
                  "move data from archTypeId: %s, tableId: %s, dataId: %s to archTypeId: "
                      + "%s, tableId: %s, dataId: %s",
                  oldArchType.getId(),
                  old.getTableId(),
                  old.getId(),
                  newArchType.getId(),
                  newDoc.getTableId(),
                  newDoc.getId()));
      logArchiveSvc.save(moveLog);
    }
  }

  private void setUserInfo(String saToken, LogArchive log) {
    log.setComId(SecurityUtil.getCropId(saToken));
    log.setFondsId(SecurityUtil.getFondsId(saToken));
    log.setUserId(SecurityUtil.getUserId(saToken));
    LoginUser loginUser = SecurityUtil.getLoginUser(saToken);
    log.setDeptId(loginUser.getDeptId());
    log.setDeptName(loginUser.getDeptName());
    log.setRoleId(loginUser.getRoleId());
    log.setUserName(loginUser.getUsername());
    log.setUserCode(loginUser.getSysUser().getAccount());
    log.setOpTime(new Date());
    log.setIp(loginUser.getIpAddress());
  }

  public List<Document> list(Document req) {
    return documentSvc.selectList(req);
  }
}
